
#include <cstdio>
#include <BIcon>
#include <BFile>
#include <BStyle>
#include <BMenu>
#include <BLabel>
#include <BButton>
#include <BPainter>
#include <BSlider>
#include <BSpinBox>
#include <BCheckBox>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BRealSpinBox>
#include <BFileDialog>
#include <BMouseEvent>
#include <BGroupBox>

#include "ChartView.h"

ChartView::ChartView(BWidget* parent) : BScrollArea(parent)
{
	_pressState = false;
	initialize();
}
ChartView::ChartView(const BString& title, BWidget* parent) : BScrollArea(title, parent)
{
	_pressState = false;
	initialize();
}
ChartView::~ChartView()
{

}

void ChartView::setVerticalLabel(const BString& verticalLabel)
{
	if (_verticalLabel != verticalLabel)
	{
		_verticalLabel = verticalLabel;
		this->fresh();
	}
}
const BString& ChartView::verticalLabel() const
{
	return  _verticalLabel;
}
const BRect& ChartView::valueLabelRect() const
{
	return _valueLabelRect;
}

void ChartView::setHorizontalLabel(const BString& horizontalLabel)
{
	if (_horizontalLabel != horizontalLabel)
	{
		_horizontalLabel = horizontalLabel;
		this->fresh();
	}
}
const BString& ChartView::horizontalLabel() const
{
	return  _horizontalLabel;
}

void ChartView::setTimeColor(const BColor& color)
{
	if (_horRuleColor != color)
	{
		_horRuleColor = color;
		this->fresh();
	}
}
const BColor& ChartView::timeColor() const
{
	return _horRuleColor;
}

void ChartView::setTimeScale(BReal timeScale)
{
	if (_timeScale != timeScale)
	{
		_timeScale = timeScale;
		_dirty = true;
		this->emit(Signal_Changed);
		this->fresh();
	}
}
BReal ChartView::timeScale() const
{
	return _timeScale;
}

void ChartView::setTimeUnit(BReal timeUnit)
{
	if (_timeUnit != timeUnit)
	{
		_timeUnit = timeUnit;
		_dirty = true;
		this->fresh();
		this->emit(Signal_Changed);
	}
}
BReal ChartView::timeUnit() const
{
	return _timeUnit;
}

void ChartView::setTimeRange(BReal minTime, BReal maxTime)
{
	setTimeRange(BRealRange(minTime, maxTime));
}
void ChartView::setTimeRange(const BRealRange& timeRange)
{
	if (_timeRange != timeRange)
	{
		_timeRange = timeRange;
		_dirty = true;
		this->emit(Signal_RangeChanged);
		this->fresh();
	}
}
const BRealRange& ChartView::timeRange() const
{
	return _timeRange;
}

void ChartView::setWheelStep(BReal wheelStep)
{
	wheelStep = bClamp(wheelStep, 0.000001, 1.0);
	if (_wheelStep != wheelStep)
	{
		_wheelStep = wheelStep;
		this->emit(Signal_StepChanged);
	}
}
BReal ChartView::wheelStep() const
{
	return _wheelStep;
}

void ChartView::setValueColor(const BColor& color)
{
	if (_verRuleColor != color)
	{
		_verRuleColor = color;
		this->fresh();
	}
}
const BColor& ChartView::valueColor() const
{
	return _verRuleColor;
}

void ChartView::setValueScale(BReal valueScale)
{
	if (_valueScale != valueScale)
	{
		_valueScale = valueScale;
		_dirty = true;
		this->fresh();
		this->emit(Signal_Changed);
	}
}
BReal ChartView::valueScale() const
{
	return _valueScale;
}

void ChartView::setValueUnit(BReal valueUnit)
{
	if (_valueUnit != valueUnit)
	{
		_valueUnit = valueUnit;
		_dirty = true;
		this->fresh();
		this->emit(Signal_Changed);
	}
}
BReal ChartView::valueUnit() const
{
	return _valueUnit;
}

void ChartView::setValueDecimals(int decimals)
{
	if (_valueDecimals != decimals)
	{
		_valueDecimals = decimals;
		_dirty = true;
		this->fresh();
		this->emit(Signal_Changed);
	}
}
int ChartView::valueDecimals() const
{
	return _valueDecimals;
}

void ChartView::setValueRange(BReal minValue, BReal maxValue)
{
	setValueRange(BRealRange(minValue, maxValue));
}
void ChartView::setValueRange(const BRealRange& valueRange)
{
	if (_valueRange != valueRange)
	{
		_valueRange = valueRange;
		_dirty = true;
		this->fresh();
		emit(Signal_RangeChanged);
	}
}
const BRealRange& ChartView::valueRange() const
{
	return _valueRange;
}

bool ChartView::addSeries(Series* series)
{
	if (series == 0)
		return false;
	if (!_seriesArray.contain(series))
	{
		_seriesArray.append(series);
		freshRanges();
		emit(Signal_Attached, series);
		connect(series, Signal_Show, &ChartView::slotSeriesVisibleChanged);
		connect(series, Signal_Hide, &ChartView::slotSeriesVisibleChanged);
		connect(series, Signal_Changed, &ChartView::slotSeriesChanged);
	}
	return true;
}
Series* ChartView::addSeries(const BString& name)
{
	Series* series = new Series(name);
	_seriesArray.append(series);
	freshRanges();
	emit(Signal_Attached, series);
	connect(series, Signal_Show, &ChartView::slotSeriesVisibleChanged);
	connect(series, Signal_Hide, &ChartView::slotSeriesVisibleChanged);
	return series;
}
bool ChartView::removeSeries(Series* series)
{
	if (series == 0)
		return false;
	if (_seriesArray.contain(series))
	{
		BHolder<Series> holder(series);
		_seriesArray.remove(series);
		emit(Signal_Detached, series);
		disconnect(series, Signal_Show);
		disconnect(series, Signal_Hide);
		disconnect(series, Signal_Changed);
		this->freshRanges();
		return true;
	}
	return false;
}
bool ChartView::removeSeries(const BString& name)
{
	for (int i = 0; i < _seriesArray.size(); i++)
	{
		Series* series = _seriesArray[i];
		if (series->name() == name)
		{
			_seriesArray.remove(i);
			emit(Signal_Detached, series);
			disconnect(series, Signal_Show);
			disconnect(series, Signal_Hide);
			this->freshRanges();
			return true;
		}
	}
	return false;
}

void ChartView::clearSeries()
{
	for (int i = 0; i < _seriesArray.size(); i++)
	{
		emit(Signal_Detached, _seriesArray[i]);
	}
	_seriesArray.clear();
	freshRanges();
}
int ChartView::seriesIndex(Series* series)
{
	return _seriesArray.find(series);
}

int ChartView::seriesCount() const
{
	return _seriesArray.size();
}
Series* ChartView::series(int index)
{
	return _seriesArray.at(index);
}
Series* ChartView::namedSeries(const char* name)
{
	for (int i = 0; i < _seriesArray.size(); i++)
	{
		Series* series = _seriesArray[i];
		if (series->name() == name)
		{
			return series;
		}
	}
	return 0;
}
Series* ChartView::namedSeries(const BString& name)
{
	for (int i = 0; i < _seriesArray.size(); i++)
	{
		Series* series = _seriesArray[i];
		if (series->name() == name)
		{
			return series;
		}
	}
	return 0;
}

void ChartView::slotSeriesVisibleChanged()
{
	this->fresh();
}
void ChartView::slotSeriesChanged()
{
	_dirty = true;
	this->fresh();
}

void ChartView::hintValueUnit()
{
	const BFont* font = this->realFont();
	BRect crect = this->centerRect();
	BRect area = this->area();
	if (area.valid() && crect.valid())
	{
		BReal visualValue = (BReal)crect.height() / area.height() * _valueRange.size();
		if (bZero(visualValue))
			return;
		int maxRows = crect.height() / (font->size() * 2);
		BRange rowRange(2, 10);
		int over = 10;
		BReal unit = _valueUnit;
		int count = 0;
		while (over-- > 0 && !rowRange.contain(count))
		{
			count = int(visualValue / unit);
			if (count < rowRange.min())
				unit /= 10;
			if (count > rowRange.max())
				unit *= 10;
		}
		if (_valueUnit != unit)
		{
			_valueUnit = unit;
			_dirty = true;
			this->fresh();
		}
	}
}
void ChartView::hintTimeUnit()
{
	BRect crect = this->centerRect();
	BRect area = this->area();
	const BFont* font = this->realFont();
	if (font && area.valid() && crect.valid())
	{
		BReal visualTime = (BReal)crect.width() / area.width() * _timeRange.size();
		if (bZero(visualTime))
			return;
		int maxColumns = crect.width() / (font->size() * 5);
		BRange columnRange(2, 20);
		BReal unit = _timeUnit;
		if (bZero(_timeUnit))
			return;
		int count = int(visualTime / unit);
		if (columnRange.contain(count))
			return;
		if (count < columnRange.min())
		{
			while (count < columnRange.min())
			{
				unit /= 10;
				count = int(visualTime / unit);
			}
		}
		else
		{
			while (count > columnRange.min())
			{
				unit *= 10;
				count = int(visualTime / unit);
			}
		}
		if (_timeUnit != unit)
		{
			_timeUnit = unit;
			_dirty = true;
			this->fresh();
		}
	}
}

BSize ChartView::sizeHint() const
{
	BSize hsize = BScrollArea::sizeHint();
	if (hsize.width() < 300)
		hsize.width() = 300;
	if (hsize.height() < 300)
		hsize.height() = 300;
	return hsize;
}

void ChartView::initialize()
{
	_frequency = 100;
	_wheelStep = BReal(0.05);
	_valueScale = 1.0f;
	_valueRange.set(0, 1000);
	_valueUnit = 1.0f;
	_valueDecimals = 3;
	_timeScale = 1.0f;
	_timeUnit = 1.0f;
	_timeRange.set(0, 1000);
	_dirty = true;

	_numberFont = new BFont("times", 14);
	_verticalLabel = "Value";
	_horizontalLabel = "Time";

	this->setAreaPolicy(Policy_Growing, Policy_Preferred);

}
const BRealPointArray& ChartView::seriesLines(int index)
{
	return _lineArraies(index);
}

void ChartView::fullView(Orientation orientation)
{
	BRect crect = this->centerRect();
	if (orientation & Orientation_Vertical)
	{
		BRealRange valueRange = this->valueRange();
		BReal valueScale = valueRange.size() / crect.height();
		this->setValueScale(valueScale);
	}
	if (orientation & Orientation_Horizontal)
	{
		BRealRange timeRange = this->timeRange();
		BReal timeScale = timeRange.size() / crect.width();
		this->setTimeScale(timeScale);
	}
}
bool ChartView::freshRanges()
{
	BRealRange valueRange;
	BRealRange timeRange;
	if (_seriesArray.size())
	{
		int i = 0;
		while (i < _seriesArray.size())
		{
			Series* series = _seriesArray[i++];
			const RealMap& valueMap = series->valueMap();
			if (valueMap.size())
			{
				valueRange.set(valueMap.min(), valueMap.max());
				timeRange.set(valueMap.begin().key(), valueMap.rbegin().key());
				break;
			}
		}
		while (i < _seriesArray.size())
		{
			Series* series = _seriesArray[i++];
			const RealMap& valueMap = series->valueMap();
			if (valueMap.size())
			{
				valueRange.expand(valueMap.min());
				valueRange.expand(valueMap.max());
				timeRange.expand(valueMap.begin().key());
				timeRange.expand(valueMap.rbegin().key());
			}
		}
	}
	if (_valueRange != valueRange || _timeRange != timeRange)
	{
		_valueRange = valueRange;
		_timeRange = timeRange;
		_dirty = true;
		this->fresh();
		emit(Signal_RangeChanged);
		return true;
	}
	return false;
}

void ChartView::scrolling(Orientation orientation)
{
	_dirty = true;
	_dirtyLines = true;
	this->fresh();
}

void ChartView::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	const BRect& crect = this->centerRect();

	_verLabelArea = this->rect(Part_Top);
	_verLabelArea.top() = _verLabelArea.bottom();
	_verLabelArea.bottom() = crect.top();

	_verRulerRect = this->rect(Part_Left);
	_verRulerRect.left() = _verRulerRect.right();
	_verRulerRect.right() = crect.left();
	_verRulerRect.top() = crect.top() + 10;
	_verRulerRect.bottom() = crect.bottom();

	_verRulerTriangle[0] = crect.leftTop();
	_verRulerTriangle[1].set(_verRulerRect.right() - 3, _verRulerRect.top());
	_verRulerTriangle[2].set(_verRulerRect.right() + 3, _verRulerRect.top());

	_horRulerRect = this->rect(Part_Bottom);
	_horRulerRect.bottom() = _horRulerRect.top();
	_horRulerRect.top() = crect.bottom();
	_horRulerRect.left() = crect.left();
	_horRulerRect.right() = crect.right() - 10;

	_horRulerTriangle[0] = crect.rightBottom();
	_horRulerTriangle[1].set(_horRulerRect.right(), _horRulerRect.top() - 3);
	_horRulerTriangle[2].set(_horRulerRect.right(), _horRulerRect.top() + 3);

	_horLabelRect = _horRulerRect;
	_dirty = true;
}

void ChartView::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	const BStyle* style = event.value();

	int fsize = style->font()->size();
	this->setPerch(Part_Top, fsize);
	this->setMargin(Part_Left, fsize);
	this->setMargin(Part_Bottom, fsize);

	_dirty = true;
}
void ChartView::freshEvent(const BEvent& event)
{
	BScrollArea::freshEvent(event);
	if (_dirty)
	{
		const BFont* font = this->realFont();
		BString minstr(_valueRange.min(), _valueDecimals);
		BString maxstr(_valueRange.max(), _valueDecimals);
		BSize textSize = bMax(font->textSize(minstr).width(), font->textSize(maxstr).width());
		this->setMargin(Part_Top, font->size() + 30);
		this->setMargin(Part_Left, textSize.width() + 5);
		this->setMargin(Part_Bottom, font->size() + 3 + font->size() + 3);

		int height = int(_valueRange.size() / _valueScale);
		int width = int(_timeRange.size() / _timeScale);
		this->setAreaSize(width, height);

		hintValueUnit();
		hintTimeUnit();

		const BRect& crect = this->centerRect();
		const BRect& area = this->area();
		BReal vlen = _valueRange.size();
		BReal tlen = _timeRange.size();
		if (area.valid() && vlen > 0 && tlen > 0)
		{
			_verPoints.reset();
			BReal verBegin = _valueRange.min() + (BReal)(area.bottom() - crect.bottom()) / area.height() * _valueRange.size();
			BReal verEnd = _valueRange.min() + (BReal)(area.bottom() - crect.top()) / area.height() * _valueRange.size();
			int valueIndex = int(verBegin / _valueUnit);
			while (_verPoints.size() < 100)
			{
				BReal value = valueIndex * _valueUnit;
				BReal y = (value - _valueRange.min()) / vlen * area.height();
				y = area.bottom() - y;
				if (value >= verEnd)
					break;
				_verPoints.append(BRealPoint(y, value));
				valueIndex++;
			}
			_horPoints.reset();
			BReal horBegin = _timeRange.min() + (BReal)(crect.left() - area.left()) / area.width() * _timeRange.size();
			BReal horEnd = _timeRange.min() + (BReal)(crect.right() - area.left()) / area.width() * _timeRange.size();
			int timeIndex = int(horBegin / _timeUnit);
			while (_horPoints.size() < 100)
			{
				BReal time = timeIndex * _timeUnit;
				BReal x = (time - _timeRange.min()) / tlen * area.width();
				x = area.x() + x;
				if (time >= horEnd)
					break;
				_horPoints.append(BPointf((float)x, (float)time));
				timeIndex++;
			}
		}
		_dirty = false;
		_dirtyLines = true;
	}
	const BRect& crect = this->centerRect();
	const BRect& area = this->area();
	if (_dirtyLines && _seriesArray.size() && area.width() > 0)
	{
		BReal vlen = _valueRange.size();
		BReal tlen = _timeRange.size();
		float width = (float)area.width();
		_lineArraies.resize(_seriesArray.size());
		for (int i = 0; i < _seriesArray.size(); i++)
		{
			Series* series = _seriesArray[i];
			BRealPointArray& linePoints = _lineArraies[i];
			linePoints.reset();
			if (series->visible())
			{
				const RealMap& valueMap = series->valueMap();
				int left = crect.left() - area.left();
				int right = crect.right() - area.left();
				BReal min = _timeRange.value((BReal)left / area.width());
				BReal max = _timeRange.value((BReal)right / area.width());
				auto begin = valueMap <= min;
				auto end = valueMap > max;
				for (auto it = begin; it <= end; ++it)
				{
					if (it.empty())
						continue;
					float x = float(area.left() + (it.key() - _timeRange.min()) / tlen * area.width());
					float y = float(area.bottom() - (it.value() - _valueRange.min()) / vlen * area.height());
					linePoints.append(BPointf(x, y));
				}
			}
		}
		_dirtyLines = false;
	}
}
void ChartView::paintEvent(const BEvent& event)
{
	BScrollArea::paintEvent(event);

	BPainter painter(this);

	BRect titleRect = this->rect(Part_Top);
	painter.setColor(Color_Text);
	if (BIcon* icon = this->icon())
	{
		painter.drawImage(titleRect.leftTop(), BSize(20), icon->image());
		titleRect.left() += 20;
	}
	painter.drawText(titleRect, this->title(), Align_LeftCenter);

	const BMargin& margin = this->margin();
	const BRect& crect = this->centerRect();
	const BRect& area = this->area();

	if (const BFont* font = painter.realFont())
	{
		_valueLabelRect = _verLabelArea.align(Align_LeftCenter, font->textSize(_verticalLabel));
	}

	painter.setFont(_numberFont);
	painter.setClip(crect);

	painter.setClip(this->size());
	painter.setColor(Color_Text);
	painter.drawText(_valueLabelRect, _verticalLabel);
	painter.setLineSmooth(true);
	painter.drawLine(_verRulerRect.rightBottom(), _verRulerRect.rightTop());
	painter.drawTriangles(_verRulerTriangle, 3);
	painter.setClip(_verRulerRect);
	for (int i = 0; i < _verPoints.size(); i++)
	{
		BReal y = _verPoints[i].x();
		BReal value = _verPoints[i].y();
		painter.drawLine((BReal)crect.left() - 1, y, (BReal)crect.left() - 5, y);
		painter.drawText(crect.left() - 6, (int)y, BString(value), Align_RightBottom);
	}

	painter.setClip(this->size());
	painter.setColor(Color_Text);
	painter.drawText(_horLabelRect, _horizontalLabel, Align_BottomCenter);
	painter.drawLine(_horRulerRect.leftTop(), _horRulerRect.rightTop());
	painter.drawTriangles(_horRulerTriangle, 3);
	painter.setClip(_horRulerRect);
	for (int i = 0; i < _horPoints.size(); i++)
	{
		BReal x = _horPoints[i].x();
		BReal time = _horPoints[i].y();
		painter.drawLine(x, (BReal)crect.bottom() + 1, x, (BReal)crect.bottom() + 5);
		painter.drawText((int)x, crect.bottom() + 5, BString(time, 3), Align_LeftTop);
	}

	BReal vlen = _valueRange.size();
	BReal tlen = _timeRange.size();

	painter.setClip(crect);
	painter.setColor(200, 200, 200);
	for (int i = 0; i < _verPoints.size(); i++)
	{
		BReal y = _verPoints[i].x();
		painter.drawLine((BReal)crect.left(), y, (BReal)crect.right(), y);
	}

	for (int i = 0; i < _horPoints.size(); i++)
	{
		BReal x = _horPoints[i].x();
		painter.drawLine(x, (BReal)crect.top(), x, (BReal)crect.bottom());
	}

	if (_seriesArray.size() && area.width() > 0)
	{
		painter.setLineSmooth(true);
		BReal width = (BReal)area.width();
		for (int i = 0; i < _seriesArray.size(); i++)
		{
			Series* series = _seriesArray[i];
			if (series->visible())
			{
				BRealPointArray& linePoints = _lineArraies[i];
				painter.setLineWidth(series->lineWidth());
				painter.setColor(series->lineColor());
				painter.setLineSmooth(true);
				painter.drawLineStrip(linePoints);
			}
		}
	}

	//BString text;
	//for (int i = 0; i < _seriesArray.size(); i++)
	//{
	//	BPointfArray& linePoints = _lineArraies[i];
	//	text << linePoints.size() << '\n';
	//}
	//text -= '\n';
	//painter.setColor(Color_Text);
	//painter.drawText(crect, text, Align_RightBottom);

	if ((_pressPoint - _releasePoint).length() > 10)
	{
		BPoint point1(_pressPoint.x(), _releasePoint.y());
		BPoint point2(_releasePoint.x(), _pressPoint.y());
		if (_pressState && Key_Ctrl)
		{
			painter.setColor(150, 100, 0);
			painter.drawQuad(_pressPoint, point1, _releasePoint, point2);
		}
		else
		{
			
		}
	}
}

void ChartView::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	BWidget::mouseLeaveEvent(mouseEvent);
	_middlePressed = false;
}
void ChartView::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	BWidget::mouseLeaveEvent(mouseEvent);
	_middlePressed = false;
}

void ChartView::mousePressEvent(const BMouseEvent& mouseEvent)
{
	BWidget::mousePressEvent(mouseEvent);
	if (mouseEvent.button() == Button_Left)
	{
		_pressState = true;
	}
	
	if (mouseEvent.button() == Button_Middle)
	{
		_pressedPoint = mouseEvent.pos();
		_pressedArea = this->area();
		_middlePressed = true;
		this->setCursor(Cursor_SizeAll);
	}
	if (mouseEvent.keyState(Key_Ctrl) && mouseEvent.button() == Button_Left)
	{
		if (_pressState)
		{
			_pressPoint = mouseEvent.pos();
		}
	}
}
void ChartView::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	BWidget::mouseReleaseEvent(mouseEvent);
	_pressState = false;
	if (mouseEvent.button() == Button_Middle)
	{
		_middlePressed = false;
		this->setCursor(Cursor_None);
	}
	if (mouseEvent.keyState(Key_Ctrl) && mouseEvent.button() == Button_Left)
	{
		BRect rect = _pressPoint;
		rect.expand(_releasePoint);

		BRect crect = this->centerRect();
		float hratio = (float)crect.width() / rect.width();
		float vratio = (float)crect.height() / rect.height();
		float ratio = bMin(hratio, vratio);
		BReal valueScale = this->valueScale() / ratio;
		BReal timeScale = this->timeScale() / ratio;
		const BRect& area = this->area();
		BPoint center = rect.center();
		BReal rx = (center.x() - area.left()) / (BReal)area.width();
		BReal ry = (center.y() - area.top()) / (BReal)area.height();
		this->setValueScale(valueScale);
		this->setTimeScale(timeScale);
		this->flush();
		center.x() = int(area.x() + area.width() * rx);
		center.y() = int(area.y() + area.height() * ry);
		this->scrollToPoint(center, Align_Center);
	}
}

void ChartView::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	BScrollArea::mouseMoveEvent(mouseEvent);
	const BPoint& pos = mouseEvent.pos();
	const BRect& crect = this->centerRect();
	if (_middlePressed)
	{
		BRect area = _pressedArea + (pos - _pressedPoint);
		this->setArea(area);
		this->fresh();
	}
	if (mouseEvent.keyState(Key_Ctrl) && mouseEvent.button() == Button_Left)
	{
		if (_pressState)
		{
			_releasePoint = mouseEvent.pos();
			this->fresh();
		}
	}
}
void ChartView::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	BScrollArea::mouseClickEvent(mouseEvent);
	if (mouseEvent.button() == Button_Right)
	{
		const BPoint& pos = mouseEvent.pos();
	}
}
void ChartView::mouseWheelEvent(const BMouseEvent& mouseEvent)
{
	int wheel = mouseEvent.wheel();
	if (mouseEvent.keyState(Key_Ctrl))
	{
		const BPoint& pos = mouseEvent.pos();
		if (_verRulerRect.contain(pos))
		{
			_valueScale += _valueScale * _wheelStep * wheel;
		}
		if (_horRulerRect.contain(pos))
		{
			_timeScale += _timeScale * _wheelStep * wheel;
		}
		if (this->centerRect().contain(pos))
		{
			_valueScale += _valueScale * _wheelStep * wheel;
			_timeScale += _timeScale * _wheelStep * wheel;
		}
		BRect area = this->area();
		if (area.valid())
		{
			float xratio = (pos.x() - area.x()) / (float)area.width();
			float yratio = (pos.y() - area.y()) / (float)area.height();
			int height = int(_valueRange.size() / _valueScale);
			int width = int(_timeRange.size() / _timeScale);
			this->setAreaSize(width, height);
			BRect rect = this->area();
			int px = int(xratio * rect.width() + rect.x());
			int py = int(yratio * rect.height() + rect.y());
			rect.move(pos.x() - px, pos.y() - py);
			this->setArea(rect);
		}
		this->emit(Signal_Changed);
		this->fresh();
		mouseEvent.accept();
		return;
	}
	BScrollArea::mouseWheelEvent(mouseEvent);
}
